package com.jt.res.interceptor;




import com.jt.res.service.RemoteProviderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

/**
 * 令牌(token:ticker-通票)拦截器
 * 其中,HandlerInterceptor为Spring MVC中的拦截器,
 * 可以在Controller方法执行之前之后执行一些动作.
 * 1)Handler 处理器(Spring MVC中将@RestController描述的类看成是处理器)
 * 2)Interceptor 拦截器
 */
public class TokenInterceptor implements HandlerInterceptor {

    private RestTemplate restTemplate;
    public TokenInterceptor(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    private RemoteProviderService remoteProviderService;
    public TokenInterceptor(RemoteProviderService remoteProviderService) {
        this.remoteProviderService = remoteProviderService;
    }

    /**
     * preHandle在目标Controller方法执行之前执行
     * @param handler 目标Controller对象
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1.从请求中获取token对象(传递token的方式:header params)
        String token = request.getHeader("token");
        //2.判断请求中是否有令牌
        if (token==null || "".equals(token))
            throw new RuntimeException("请先登陆");
        //3.判断令牌是否过期
        //去认证中心校验
        //基于RestTemplate远程调用
//        String url = "http://jt-sso-auth/auth/info?token="+token;
//        Map<String,Object> map = restTemplate.getForObject(url,Map.class);
        //4.解析token中的认证和权限信息(一般存储在jwt格式中的负载部分)
        //去认证中心解析
        Map<String, Object> map = remoteProviderService.echoMsg(token);
        Boolean expired = (Boolean) map.get("expired");
        if (expired) throw new RuntimeException("登陆超时");
        String username = (String) map.get("username");
        List<String> list = (List<String>) map.get("authorities");


        //5.封装和存储认证和权限信息
        //5.1构建UserDetail对象(用户身份的象征-类似于一张名片,微信的二维码)
        UserDetails userDetails = User.builder()
                .username(username)
                .password("")
                .authorities(list.toArray(new String[]{}))
                .build();
        //5.2构建Security权限交互对象(固定写法)
        PreAuthenticatedAuthenticationToken authToken = new
                PreAuthenticatedAuthenticationToken(
                        userDetails,//用户身份
                        userDetails.getPassword(),
                        userDetails.getAuthorities());
        //5.3将权限交互对象与当前请求进行绑定
        authToken.setDetails(new WebAuthenticationDetails(request));
        //5.4.将认证后的token存储到Security上下文(会话对象)
        SecurityContextHolder.getContext().setAuthentication(authToken);
        return true;//true表示放行,false表示拦截到请求以后,不再继续传递
    }
}
